import copy
import datetime
import json
import math
import socket

import geopandas as gpd
import numpy as np
import pytz
from django.core.serializers import serialize
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
from django.views.generic.base import View
from django.db.models import Q

import web.RegionalPlan.network as nx
from .models import Trajectory, userDriver, userAdmin


# 路由中指定要调用的函数,传入一个用户请求参数
def get_host_ip():
    """
    查询本机ip地址
    :return:
    """
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()

    return ip


localhost = get_host_ip()


def getLogin(request):
    '''返回index界面'''
    # 返回HTML页面时,使用render来渲染和打包
    return render(request, 'login.html')


def getSignUp(request):
    '''返回index界面'''
    # 返回HTML页面时,使用render来渲染和打包
    return render(request, 'signup.html')


def userLogin(request):
    username = request.POST['username']
    password = request.POST['password']
    driverORadmin = request.POST['driverORadmin']
    if driverORadmin == 'driver':
        querylogin = userDriver.objects.filter(Q(username__exact=username) & Q(password__exact=password))
        if querylogin.exists():
            ResultJson = {'username': username, 'status': 'completed'}
        else:
            ResultJson = {'username': username, 'status': 'ERROR, Incorrect username or password'}
    elif driverORadmin == 'admin':
        querylogin = userAdmin.objects.filter(Q(username__exact=username) & Q(password__exact=password))
        if querylogin.exists():
            ResultJson = {'username': username, 'status': 'completed'}
        else:
            ResultJson = {'username': username, 'status': 'ERROR, Incorrect username or password'}

    return HttpResponse(json.dumps(ResultJson, ensure_ascii=False),
                        content_type="application/json,charset=utf-8")


def userSignUp(request):
    username = request.POST['username']
    password = request.POST['password']
    email = request.POST['email']
    driverORadmin = request.POST['driverORadmin']
    if driverORadmin == 'driver':
        query_name = userDriver.objects.filter(username__exact=username)
        query_email = userDriver.objects.filter(email__exact=email)
        if query_name.exists() and query_email.exists():
            ResultJson = {'username': username, 'status': 'username and email have been signed up'}
        elif query_email.exists() and (not query_name.exists):
            ResultJson = {'username': username, 'status': 'email has been signed up'}
        elif query_name.exists() and (not query_email.exists):
            ResultJson = {'username': username, 'status': 'username has been signed up'}
        else:
            driver_model = userDriver(username=username, password=password, email=email, driverORadmin='driver')
            driver_model.save()
            ResultJson = {'username': username, 'status': 'completed'}
    elif driverORadmin == 'admin':
        query_name = userAdmin.objects.filter(username__exact=username)
        query_email = userAdmin.objects.filter(email__exact=email)
        if query_name.exists() and query_email.exists():
            ResultJson = {'username': username, 'status': 'username and email have been signed up'}
        elif query_email.exists() and (not query_name.exists):
            ResultJson = {'username': username, 'status': 'email has been signed up'}
        elif query_name.exists() and (not query_email.exists):
            ResultJson = {'username': username, 'status': 'username has been signed up'}
        else:
            admin_model = userAdmin(username=username, password=password, email=email, driverORadmin='admin')
            admin_model.save()
            ResultJson = {'username': username, 'status': 'completed'}

    return HttpResponse(json.dumps(ResultJson, ensure_ascii=False),
                        content_type="application/json,charset=utf-8")


def login2main(request):
    user_msg = 'http://'+localhost+':8000/web/hotpot/'
    return render(request, 'hotpot.html', {"user_msg": user_msg})


# 路由中指定要调用的函数,传入一个用户请求参数
def statusQuery(request):
    with open('./web/static/data/trafficflowwh.json', 'r', encoding='utf8')as fp:
        feature_collection = json.load(fp)
    return JsonResponse(feature_collection)


def getroute(request):
    return render(request, 'route.html')


def traffic(request):
    track_url = '../static/data/trafficflowwh.json'
    return render(request, 'traffic.html', {"track_url": track_url})


# def getIndex(request):
#     '''返回index界面'''
#     # 返回HTML页面时,使用render来渲染和打包
#     return render(request, 'index.html')

def getHotpot(request):
    '''返回hotpot界面'''
    # 返回HTML页面时,使用render来渲染和打包
    # 轨迹点的url
    track_url = 'http://'+localhost+':8080/geoserver/taxidm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=wuhan%3Atrackpoints_test&maxFeatures=50000&outputFormat=application%2Fjson'
    return render(request, 'hotpot.html', {"track_url": track_url})


def calcQuery(request):
    # 返回HTML页面时,使用render来渲染和打包
    # 轨迹点的url
    querytime = datetime.datetime(2018, 11, 11, 3, 35, 0, 0, tzinfo=(pytz.timezone('Asia/Shanghai')))
    geojson = serialize('geojson', Trajectory.objects.filter(locatedtime__gt=querytime),
                        geometry_field='geom',
                        fields=('taxiid', 'locatedtime', 'empty_load', 'speed', 'direction'))
    return HttpResponse(geojson)


def pitchQuery(request):
    # 返回HTML页面时,使用render来渲染和打包
    # 轨迹点的url
    pitchlevel = int(request.POST['pitchlevel'])
    if (request.POST['taxiid'] == '--不限--'):
        geojson = serialize('geojson', Trajectory.objects.filter(speed__gte=pitchlevel),
                            geometry_field='geom',
                            fields=('taxiid', 'locatedtime', 'empty_load', 'speed', 'direction'))
    else:
        geojson = serialize('geojson', Trajectory.objects.filter(Q(taxiid__exact=request.POST['taxiid'])&Q(speed__gte=pitchlevel)),
                            geometry_field='geom',
                            fields=('taxiid', 'locatedtime', 'empty_load', 'speed', 'direction'))
    geojson = json.loads(geojson)
    ResultJson = {'geojson': geojson}
    return HttpResponse(json.dumps(ResultJson, ensure_ascii=False),
                        content_type="application/json,charset=utf-8")


def taxiidQuery(request):
    taxiid = list(Trajectory.objects.values_list("taxiid"))
    taxiidlist = list(set([int(x[0]) for x in taxiid]))
    taxiidlist = sorted(taxiidlist)
    ResponseResult = {'idlist': taxiidlist}
    return HttpResponse(json.dumps(ResponseResult, ensure_ascii=False),
                        content_type="application/json,charset=utf-8")


def getTrackrecall(request):
    track_url = 'http://' + localhost + ':8000/web/calcQuery/'
    return render(request, 'trackrecall.html', {"track_url": track_url})


def getTrackPoint(request):
    """[获取轨迹点]

    Args:
        request ([type]): [前端请求]
    """
    track_url = 'http://'+localhost+':8080/geoserver/taxidm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=taxidm%3Atrackpoints_test&maxFeatures=50000&outputFormat=application%2Fjson'
    return HttpResponse(track_url)


def getDrivingfeature(request):
    return render(request, 'drivingfeature.html')


def getDriverprofile(request):
    return render(request, 'driverprofile.html')


def network(request):
    """[渲染网络页面]

    Args:
        request ([type]): [前端请求]

    Returns:
        [render]: [渲染页面]
    """

    return render(request, 'network.html')


def ShowClustering(request):
    """[返回颜色列表]]

    Args:
        request ([request]): [前端请求]

    Returns:
        [JsonResponse]: [将颜色列表组织为json返回给前端]
    """
    # 读取颜色列表并转为list
    color_list = []
    for line in open("./web/static/data/color_list.txt", 'r'):  # 打开文件
        color = line.replace('\n', '')  # 替换换行符
        color_list.append(color)
    return JsonResponse({"color_list": color_list})


def GetEdgedata(request):
    """[获取网络边权重]

    Args:
        request ([type]): [前端发送的请求]

    Returns:
        [request]: [返回边权重的json文件]
    """
    with open('./web/static/data/edgeData.json', 'r', encoding='utf8')as fp:
        feature_collection = json.load(fp)

    return JsonResponse(feature_collection)


def GetEdgedata_real(request):
    """[获取网络边权重,完整函数但时间较长]

    Args:
        request ([type]): [前端发送的请求]

    Returns:
        [request]: [返回边权重的json文件]
    """
    od_df = gpd.read_file('./web/static/data/ODPoint.geojson')
    nodeData = []
    for index, row in od_df.iterrows():
        nodeData.append(row['HotPot'])
    nodeData = list(set(nodeData))
    node_len = len(nodeData)
    edges = [[0] * node_len] * node_len
    n = len(od_df)
    for i in range(0, n, 2):
        if (od_df[i]['pickAndDrop'] != od_df[i + 1]['pickAndDrop']):
            edges[od_df[i]['HotPot']][od_df[i]['HotPot']] += 1
    edgedata = {}
    for a in range(0, node_len):
        for b in range(0, node_len):
            if (edges[a][b] != 0):
                temp = {"source": a, "target": b, "weight": edges[a][b]}
                edgedata.append(temp)
    return JsonResponse({"nodeData": nodeData, "edgeData": edgedata})


class DBScan(View):
    def get(self, request):
        return HttpResponse("helloworld!")

    def post(self, request):
        value = request.POST.get('key', '')
        with open('./web/static/data/ODPoint.geojson', 'r', encoding='utf8')as fp:
            feature_collection = json.load(fp)
        return JsonResponse(feature_collection)

    def post_real(self, request):
        od_df = nx.gpd.read_file(
            'http://' + localhost + ':8080/geoserver/taxidm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=wuhan%3Aodpoint&maxFeatures=10000&outputFormat=application%2Fjson')
        sample_OD_df = od_df[:10000]
        lat_lon_df = sample_OD_df[['纬度', '经度']].dropna(axis=0, how='all')
        # 距离矩阵计算
        distance_matrix = nx.squareform(nx.pdist(lat_lon_df, (lambda u, v: nx.haversine(u, v))))
        # DBScan聚类
        db = nx.DBSCAN(eps=200, min_samples=10, metric='precomputed').fit_predict(distance_matrix)
        od_label = db.tolist()  # 使用DBSCAN获得的热点聚类标签
        noise = 0
        for l in od_label:
            if l == -1:
                noise += 1
        label_str = [str(ol) for ol in list(set(od_label))]  # 确定出租车OD热点类簇的数目与类型
        sample_OD_df['热点类别'] = od_label
        filtered_df = nx.drop_noise(sample_OD_df)
        filtered_df.reset_index(drop=True, inplace=True)
        print('清洗噪声后OD点数：' + str(len(filtered_df)))

        filtered_df = nx.pd.DataFrame(filtered_df)
        filtered_df = filtered_df.reset_index(drop=True)
        features = []
        for index, row in filtered_df.iterrows():
            lng = row['经度']
            lat = row['纬度']
            m_point = nx.Point((float(lng), float(lat)))
            if row['上下车'] == '上车点':
                a = 'pick'
            else:
                a = 'drop'
            features.append(
                nx.Feature(geometry=m_point, properties={"id": row['id'], 'pickAndDrop': a, 'HotPot': row['热点类别']}))
        feature_collection = nx.FeatureCollection(features=features)
        return JsonResponse(feature_collection)


def getCityPlan(request):
    '''返回cityplan界面'''
    # 返回HTML页面时,使用render来渲染和打包
    POI_url = 'http://' + localhost + ':8080/geoserver/taxidm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=wuhan%3Awhpoi&maxFeatures=50000&outputFormat=application%2Fjson'
    return render(request, 'city_plan.html', {"POI_url": POI_url})


class CityPlanKmeans(View):
    def get(self, request):
        return HttpResponse("yes！")

    def post(self, request):
        value = request.POST.get('key', '')
        with open('./web/static/data/KCenterPoint.geojson', 'r', encoding='utf8')as fp:
            feature_collection = json.load(fp)
        return JsonResponse(feature_collection)

    def post_real(self, request):
        # 该函数为真实执行函数
        od_df = nx.gpd.read_file(
            'http://' + localhost + ':8080/geoserver/taxidm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=wuhan%3Awhpoi&maxFeatures=50000&outputFormat=application%2Fjson')
        sample_OD_df = od_df[:10000]
        lat_lon_df = sample_OD_df[['纬度', '经度']].dropna(axis=0, how='all')
        # 距离矩阵计算
        distance_matrix = nx.squareform(nx.pdist(lat_lon_df, (lambda u, v: nx.haversine(u, v))))
        # DBScan聚类
        db = nx.DBSCAN(eps=200, min_samples=10, metric='precomputed').fit_predict(distance_matrix)
        od_label = db.tolist()  # 使用DBSCAN获得的热点聚类标签
        noise = 0
        for l in od_label:
            if l == -1:
                noise += 1
        label_str = [str(ol) for ol in list(set(od_label))]  # 确定出租车OD热点类簇的数目与类型
        sample_OD_df['热点类别'] = od_label
        filtered_df = nx.drop_noise(sample_OD_df)
        filtered_df.reset_index(drop=True, inplace=True)
        print('清洗噪声后OD点数：' + str(len(filtered_df)))

        filtered_df = nx.pd.DataFrame(filtered_df)
        filtered_df = filtered_df.reset_index(drop=True)
        features = []
        for index, row in filtered_df.iterrows():
            lng = row['经度']
            lat = row['纬度']
            m_point = nx.Point((float(lng), float(lat)))
            if row['上下车'] == '上车点':
                a = 'pick'
            else:
                a = 'drop'
            features.append(
                nx.Feature(geometry=m_point, properties={"id": row['id'], 'pickAndDrop': a, 'HotPot': row['热点类别']}))
        feature_collection = nx.FeatureCollection(features=features)
        return JsonResponse(feature_collection)


# def driverquery(request):
#     month = request.GET['month']
#     driver = ['23355210', '34740660', '38966370', '43505790', '45532170', '92120880', '95117310']
#     driverPerformance = {'23355210': [0] * 30, '34740660': [0] * 30, '38966370': [0] * 30, '43505790': [0] * 30,
#                          '45532170': [0] * 30, '92120880': [0] * 30, '95117310': [0] * 30}
#     lonlatdict = {'23355210': [], '34740660': [], '38966370': [], '43505790': [],
#                   '45532170': [], '92120880': [], '95117310': []}
#     timedict = copy.deepcopy(lonlatdict)
#
#     for i in range(30):
#         driverdata = shenzhantrack.objects.filter(locatedtime__month=month, locatedtime__day=i + 1)
#         print(i)
#         for tmp in driverdata:
#             driverPerformance[tmp.taxiid][i] = driverPerformance[tmp.taxiid][i] + 1
#             lonlatdict[tmp.taxiid].append([tmp.longitude, tmp.latitude])
#             timedict[tmp.taxiid].append(tmp.locatedtime)
#         driverPerformance['23355210'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['23355210'][i] / 2)]
#         driverPerformance['34740660'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['34740660'][i] / 2)]
#         driverPerformance['38966370'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['38966370'][i] / 2)]
#         driverPerformance['43505790'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['43505790'][i] / 2)]
#         driverPerformance['45532170'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['45532170'][i] / 2)]
#         driverPerformance['92120880'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['92120880'][i] / 2)]
#         driverPerformance['95117310'][i] = [str(month) + '-' + str(i + 1), int(driverPerformance['95117310'][i] / 2)]
#
#     disdict = {'23355210': 0, '34740660': 0, '38966370': 0, '43505790': 0,
#                '45532170': 0, '92120880': 0, '95117310': 0, }
#     for key, value in lonlatdict.items():
#         lastlonlat = value[0]
#         for i in range(1, len(value)):
#             disdict[key] = disdict[key] + math.sqrt(
#                 pow(value[i][0] - lastlonlat[0], 2) + pow(value[i][1] - lastlonlat[1], 2)) * 11132
#             lastlonlat = value[i]
#     sumdis = 0
#     for key, value in disdict.items():
#         sumdis = sumdis + value / 1000
#
#     timeperdict = {'23355210': 0, '34740660': 0, '38966370': 0, '43505790': 0,
#                    '45532170': 0, '92120880': 0, '95117310': 0, }
#     for key, value in timedict.items():
#         lasttime = value[0]
#         for i in range(1, len(value)):
#             if ((value[i] - lasttime).seconds > 60 * 5):
#                 continue
#             else:
#                 timeperdict[key] = timeperdict[key] + (value[i] - lasttime).seconds / 60  # ?
#                 lasttime = value[i]
#     sumtime = 0
#     for key, value in timeperdict.items():
#         sumtime = sumtime + value
#
#     arrdriver = np.zeros([7, 30])
#     indexcol = 0
#     for key, value in driverPerformance.items():
#         for i in range(len(value)):
#             arrdriver[indexcol, i] = value[i][1]
#         indexcol = indexcol + 1
#
#     dailyPerformance = np.sum(arrdriver, axis=0)
#     meanday = np.mean(dailyPerformance)
#     maxday = np.max(dailyPerformance)
#     minday = np.min(dailyPerformance)
#     drivernum = np.sum(arrdriver, axis=1)
#     driverorder = np.argsort(-drivernum).tolist()
#     top1 = driver[driverorder[0]]
#     top2 = driver[driverorder[1]]
#     top3 = driver[driverorder[2]]
#     top4 = driver[driverorder[3]]
#     sumPerformance = np.sum(arrdriver)
#     top1num = drivernum[driverorder[0]]
#     top1percent = top1num / sumPerformance
#
#     ResponseResult = {'driverPerformance': driverPerformance, 'meanday': meanday, 'maxday': maxday, 'minday': minday,
#                       'top1': top1, 'top2': top2, 'top3': top3, 'top4': top4, 'sumPerformance': sumPerformance,
#                       'top1num': top1num, 'top1percent': top1percent, 'sumdis': sumdis, 'sumtime': sumtime}
#     return HttpResponse(json.dumps(ResponseResult, ensure_ascii=False),
#                         content_type="application/json,charset=utf-8")


def poiQuery(requesert):
    """[查询poi列表]

    Args:
        requesert ([type]): [description]
    """
    poi_df = gpd.read_file(
        'http://' + localhost + ':8080/geoserver/taxidm/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=wuhan%3Awhpoi&maxFeatures=50000&outputFormat=application%2Fjson')
    poi_list = []
    for index, row in poi_df.iterrows():
        poi_list.append(row['fclass'])
    poi_list = list(set(poi_list))
    poi_list = sorted(poi_list)
    return JsonResponse({"poi_list": poi_list})


def statusQuery(request):
    with open('./web/static/data/trafficflowwh.json', 'r', encoding='utf8')as fp:
        feature_collection = json.load(fp)
    return JsonResponse(feature_collection)


def traffic(request):
    track_url = '../static/data/trafficflowwh.json'
    return render(request, 'traffic.html', {"track_url": track_url})
